package com.fgba.express.security;


import com.fgba.express.comm.result.ResultCode;
import com.fgba.express.data.entity.User;
import com.fgba.express.data.service.IUserService;
import com.fgba.express.util.JwtUtils;
import com.fgba.express.util.RedisUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author fgba
 */
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private IUserService userService;

    @Resource
    private UserDetailsServiceImpl userDetailsService;
    @Resource
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String jwt = request.getHeader(jwtUtils.getHeader());
        boolean isWx = "wx".equals(request.getHeader("request-from"));
        if (jwt == null || "".equals(jwt)) {
            chain.doFilter(request, response);
            return;
        }

        Claims claim = jwtUtils.getClaimByToken(jwt);
        try {
            if (claim == null) {
                throw new JwtAuthenticationException(ResultCode.TOKEN_ERROR);
            }
            if (jwtUtils.isTokenExpired(claim)) {
                throw new JwtAuthenticationException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
            }
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken;
            String key = claim.getSubject();
            String authorities = (String) redisUtil.get(key);

            if (authorities != null) {
                usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(key, null, userDetailsService.getAuthorities(authorities));
            } else {
                User user;
                if (isWx) {
                    user = userService.getUserByWxId(key);
                } else {
                    user = userService.getUserByUsername(key);
                }
                if (user == null) {
                    throw new JwtAuthenticationException(ResultCode.USER_ACCOUNT_NOT_EXIST);
                }
                usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(key, null,
                        userDetailsService.getAuthorities(userService.getUserAuthorityInfo(user.getId())));
            }


            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            chain.doFilter(request, response);
        } catch (JwtAuthenticationException e) {
            jwtAuthenticationEntryPoint.commence(request, response, e);
        }

    }


}
